﻿using System;
using System.IO;
using System.Windows;
using AdTech.Snap.Interop;
using Microsoft.Win32;

namespace AdTech.Snap
{
    /// <summary>
    /// The core of Snap.
    /// </summary>
    public class SnapFactory : ISnapFactory, IDrawableRectangle
    {
        // Fields
        private readonly IConfiguration configModel;
        private Point startPosition;
        private Rect drawedRectangle;

        // Properties
        /// <summary>
        /// Gets the resulting destination path.
        /// </summary>
        public string DestinationPath { get { return this.configModel.DefaultFileDestination; } }
        /// <summary>
        /// Gets a value whether the rectangle is currently being drawn.
        /// </summary>
        public bool IsDrawing { get; private set; }

        // Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="AdTech.Snap.SnapFactory"/> class.
        /// </summary>
        public SnapFactory(IConfiguration configModel)
        {
            this.configModel = configModel;
        }

        // Public Methods
        /// <summary>
        /// Creates a new instance of the <see cref="AdTech.Snap.SnapFactory"/> class.
        /// </summary>
        public static ISnapFactory Create(IConfiguration configModel)
        {
            return new SnapFactory(configModel);
        }

        #region ISnapFactory Members
        /// <summary>
        /// Captures a new screenshot with the given coordinates.
        /// </summary>
        /// <param name="destination">The destination path.</param>
        /// <param name="position">The top left position of the rectangle to crop.</param>
        /// <param name="size">The size of rectangle to crop.</param>
        public void CaptureScreen(string destination, Point position, Size size)
        {
            int x = Convert.ToInt32(position.X);
            int y = Convert.ToInt32(position.Y);
            int w = Convert.ToInt32(size.Width);
            int h = Convert.ToInt32(size.Height);
            CaptureScreenHelper.CopyFromScreen(destination, x, y, w, h);
        }

        /// <summary>
        /// Determines the destination for a screenshot.
        /// </summary>
        /// <returns>The configured default destination path if set or a user specified path through a SaveFileDialog.</returns>
        public string SelectDestination()
        {
            if (String.IsNullOrEmpty(this.configModel.DefaultFileDestination))
            {
                SaveFileDialog dlg = new SaveFileDialog
                {
                    DefaultExt = "png",
                    Filter = "PNG Files|*.png"
                };
                if (dlg.ShowDialog().Equals(true))
                    return dlg.FileName;
            }
            return BuildDestinationPath(this.configModel.DefaultFileDestination);
        }
        #endregion

        #region IDrawableRectangle Members
        /// <summary>
        /// Initiates drawing.
        /// </summary>
        /// <param name="startPosition">The point the rectangle is drawn from.</param>
        public void StartDrawing(Point startPosition)
        {
            this.IsDrawing = true;
            this.startPosition = startPosition;
        }

        /// <summary>
        /// Extends the rectangle to be drawn to the given point.
        /// </summary>
        /// <param name="absoluteCurrentPosition">The current position.</param>
        public void Draw(Point absoluteCurrentPosition)
        {
            if (this.IsDrawing)
                this.drawedRectangle = new Rect(this.startPosition, absoluteCurrentPosition);
        }

        /// <summary>
        /// Finishes drawing.
        /// </summary>
        public void FinishDrawing()
        {
            if (this.IsDrawing)
                this.IsDrawing = false;
        }

        /// <summary>
        /// Gets the drawn rectangle relative to the client.
        /// </summary>
        /// <returns>The rectangle relative to the client.</returns>
        public Rect GetDrawedRectangle() { return this.GetDrawedRectangle(IntPtr.Zero); }

        /// <summary>
        /// Gets the drawn rectangle relative to screen.
        /// </summary>
        /// <param name="relativeToScreen">The handle of a window.</param>
        /// <returns>The rectangle relative to screen.</returns>
        public Rect GetDrawedRectangle(IntPtr relativeToScreen)
        {
            return relativeToScreen == IntPtr.Zero ? this.drawedRectangle : WindowInteropFactory.ClientToScreen(this.drawedRectangle, relativeToScreen);
        }
        #endregion

        // Protected Methods
        /// <summary>
        /// Creates the destination path for a created screenshot by generating a uniquely named temporary filename.
        /// </summary>
        /// <param name="dir">The target directory.</param>
        /// <returns>The destination path.</returns>
        protected virtual string BuildDestinationPath(string dir)
        {
            string fileName = Path.GetFileNameWithoutExtension(Path.GetTempFileName());
            fileName = String.Concat(fileName.ToLower(), ".png");
            return Path.Combine(dir, fileName);
        }
    }
}
